package com.enlighten.aio.td.service.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import javax.annotation.Resource;

import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.enlighten.aio.db.Enum.OrderStatus;
import com.enlighten.aio.db.Enum.PaymentStatus;
import com.enlighten.aio.db.mapper.AddressMapper;
import com.enlighten.aio.db.mapper.CatalogMapper;
import com.enlighten.aio.db.mapper.OrderItemMapper;
import com.enlighten.aio.db.mapper.OrderMapper;
import com.enlighten.aio.db.mapper.PaymentMapper;
import com.enlighten.aio.db.model.Catalog;
import com.enlighten.aio.db.model.Order;
import com.enlighten.aio.db.model.OrderItem;
import com.enlighten.aio.db.model.Payment;
import com.enlighten.aio.td.service.OrderService;
import com.enlighten.aio.td.service.model.in.OrderIn;
import com.enlighten.aio.td.service.model.out.OrderOut;
import com.enlighten.aio.td.service.model.out.PayOut;
import com.x.share.db.model.Pagination;
import com.x.share.mid.exception.HelperException;
import com.x.share.mid.http.client.SSLHttpClient;
import com.x.share.mid.prop.AlipayProperties;
import com.x.share.mid.prop.ShareProperties;
import com.x.share.mid.prop.WxProperties;
import com.x.share.mid.utils.AliPayUtils;
import com.x.share.mid.utils.WxPayUtils;


@Service
public class OrderServiceImpl implements OrderService{

	Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
	
	@Resource
	AddressMapper addressMapper;
	@Resource
	CatalogMapper catalogMapper;
	@Resource
	OrderMapper orderMapper;
	@Resource
	OrderItemMapper orderItemMapper;
	@Resource
	PaymentMapper paymentMapper;
	@Resource
	WxProperties wxProperties;
	@Resource
	AlipayProperties alipayProperties;
	@Resource
	ShareProperties shareProperties;
	
	/*
	@Override
	public OrderOut createOrder(CatalogIn in, Long userId) {
		Order order = new Order();
		Address address = addressMapper.selectByPrimaryKey(in.getAddressId());
		Catalog catalog = catalogMapper.selectByPrimaryKey(in.getCatalogId());
		if(address == null) {
			throw new HelperException("非法收货地址，无法创建订单，请选择正确收货地址！");
		}
		DateTime now = new DateTime();
		Random random = new Random();
		String oid = String.format("%s%s", now.toString("YYYYMMddHHmmssSS"),random.nextInt(899999) + 1000000);
		Integer total = in.getPrice() * in.getNum();
		order.setId(oid);
		order.setCatalogId(in.getCatalogId());
		order.setPrice(total);
		order.setAddressId(in.getAddressId());
		order.setProductName(catalog.getName());
		order.setUserId(userId);
		order.setProductNum(in.getNum());
		order.setState(OrderStatus.NEW.getCode());
		order.setCreateDate(new Date());
		orderMapper.insert(order);
		return OrderOut.from(order);
	}*/

	@Override
	public Pagination<OrderOut> listMyOrders(Long userId, String status, Integer pageNo,
			Integer pageSize) {
		/*List<Order> orders = orderMapper.filterBy(userId, null, status, Pagination.offset(pageNo, pageSize), Pagination.limit(pageSize));
		int records = orderMapper.countBy(userId, null, status);
		Pagination<OrderOut> page = new Pagination<OrderOut>(pageNo, pageSize);
		List<OrderOut> list = Lists.newArrayList();
		orders.forEach(s ->{
			list.add(OrderOut.from(s));
		});
		page.setItems(list);
		page.setRecords(records);
		*/
		return null;
	}

	@Override
	public Integer removeOrder(String orderId, Long userId) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public OrderOut getOrder(String orderId) {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Transactional
	@Override
	public PayOut createOrderWithWxQrCode2(OrderIn in) throws HelperException {
		PayOut out = createOrder(in);
		Map<String, Object> qrMap = wxPayQrCode2(out);
		if (qrMap != null && qrMap.get("return_code").equals("SUCCESS")) {
			if (qrMap.get("result_code").equals("SUCCESS")) {
				String codeUrl = qrMap.get("code_url").toString();
				out.setWxQrCode2Url(codeUrl);
			}
		}
		return out;
	}

	private Map<String, Object> wxPayQrCode2(PayOut out) {
		String wxAppId = wxProperties.getAppId();
		String wxMerchantId = wxProperties.getMerchantId();
		String wxSpbillIp = wxProperties.getSpbillIp();
		String wxMerchantKey = wxProperties.getMerchantKey();
		String apiGateway = shareProperties.getApiGateway();

		SortedMap<String, String> mp = new TreeMap<String, String>();
		mp.put("appid", wxAppId);
		mp.put("mch_id", wxMerchantId);
		mp.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));
		mp.put("body", out.getOrder().getName());
		mp.put("out_trade_no", out.getOrder().getId().toString());
		// 微信支付全额单位为分
		mp.put("total_fee", String.valueOf(out.getPayment().getFee().multiply(new BigDecimal("100")).intValue()));
		mp.put("spbill_create_ip", wxSpbillIp);
		mp.put("notify_url", String.format("%s/%s", apiGateway, "td/wxpay/notify"));
		mp.put("trade_type", "NATIVE");
		String sign = WxPayUtils.md5Sign(mp, wxMerchantKey);
		mp.put("sign", sign);
		String xml = WxPayUtils.convert2Xml(mp);
		logger.info(">>>> wx qr code pay(2): {} >>>", xml);
		try {
			SSLHttpClient client = new SSLHttpClient(wxProperties.getCertPath(), wxMerchantId);
			String result = client.post("https://api.mch.weixin.qq.com/pay/unifiedorder", xml);
			logger.info(">>>> wx qr code pay result: {}", result);
			Map<String, Object> rltMap = WxPayUtils.xml2Map(result);
			return rltMap;
		} catch (Exception e) {
			logger.warn("!!!! exception: {}", e);
		}
		return null;
	}
	
	@Transactional
	@Override
	public PayOut createOrder(OrderIn in) throws HelperException {
		logger.info(">>>> create order with: {}", JSON.toJSONString(in));
		Random random = new Random();
		
		String oid = String.format("%s%s",new DateTime().toString("YYYYMMddHHmmssSS"),random.nextInt(899999) + 1000000);
		Catalog c = catalogMapper.selectByPrimaryKey(in.getCatalogId());
		Date now = new Date();
		Order order = new Order();
		order.setId(oid);
		order.setUserId(in.getUserId());
		order.setCatalogId(in.getCatalogId());
		order.setName(c.getName());
		order.setAddressId(in.getAddressId());
		order.setFee(c.getPrice().multiply(new BigDecimal(in.getQuantity().toString())));
		order.setState(OrderStatus.NEW.getCode());
		order.setCreateDate(now);
		orderMapper.insert(order);

		OrderItem item = new OrderItem();
		item.setUserId(order.getUserId());
		item.setCatalogId(in.getCatalogId());
		item.setOrderId(oid);
		item.setName(c.getName());
		item.setPrice(item.getPrice());
		item.setQuantity(in.getQuantity());
		item.setFee(order.getFee());
		item.setStatus(order.getState());
		item.setCreateTime(now);
		item.setUpdateTime(now);
		orderItemMapper.insert(item);

		Payment pay = new Payment();
		pay.setOrderId(order.getId());
		pay.setUserId(order.getUserId());
		pay.setCatalogId(order.getCatalogId());
		pay.setFee(order.getFee());
		pay.setStatus(PaymentStatus.NEW.getCode());
		pay.setCreateDate(now);
		pay.setUpdateDate(now);
		paymentMapper.insert(pay);
		return PayOut.from(order, item, pay);
	}

	@Transactional
	@Override
	public String createOrderWithAliPagePay(OrderIn in) throws HelperException {
		AlipayClient client = AliPayUtils.getAlipayClient(alipayProperties);
		String apiGateway = shareProperties.getApiGateway();
		AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
		PayOut out = createOrder(in);
		JSONObject mp = new JSONObject();
		mp.put("out_trade_no", out.getOrder().getId());
		// 支付宝支付单位为元
		// DecimalFormat format = new DecimalFormat("#0.00");
		// String fee = format.format(Float.valueOf(out.getFee()) / 100);
		mp.put("total_amount", out.getPayment().getFee());
		mp.put("subject", out.getOrder().getName());
		mp.put("body", out.getOrder().getName());
		mp.put("product_code", "FAST_INSTANT_TRADE_PAY");
		request.setBizContent(mp.toJSONString());
		request.setReturnUrl(in.getReturnUrl());
		request.setNotifyUrl(String.format("%s/%s", apiGateway, "td/alipay/notify"));
		logger.info(">>>> alipay request param: {}", mp.toJSONString());
		try {
			return client.pageExecute(request).getBody();
		} catch (AlipayApiException e) {
			logger.warn("!!!! alipay api exception: ", e);
			return null;
		}
	}
}
	
	/*
	@Transactional
	@Override
	public String createOrderWithAliPagePay(OrderIn in) throws HelperException {
		AlipayClient client = AliPayUtils.getAlipayClient(alipayProperties);
		String apiGateway = shareProperties.getApiGateway();
		AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
		PayOut out = createOrder(in);
		JSONObject mp = new JSONObject();
		mp.put("out_trade_no", out.getOrder().getId());
		// 支付宝支付单位为元
		// DecimalFormat format = new DecimalFormat("#0.00");
		// String fee = format.format(Float.valueOf(out.getFee()) / 100);
		mp.put("total_amount", out.getPayment().getFee());
		mp.put("subject", out.getOrder().getName());
		mp.put("body", out.getOrder().getName());
		mp.put("product_code", "FAST_INSTANT_TRADE_PAY");
		request.setBizContent(mp.toJSONString());
		request.setReturnUrl(in.getReturnUrl());
		request.setNotifyUrl(String.format("%s/%s", apiGateway, "td/alipay/notify"));
		logger.info(">>>> alipay request param: {}", mp.toJSONString());
		try {
			return client.pageExecute(request).getBody();
		} catch (AlipayApiException e) {
			logger.warn("!!!! alipay api exception: ", e);
			return null;
		}
	}

	@Override
	public PayOut getOrder(long orderId) {
		TdOrder order = new TdOrder().selectById(orderId);
		TdPayment pay = new TdPayment().selectOne("order_id = {0}", orderId);
		TdOrderItem item = new TdOrderItem().selectList("order_id = {0}", orderId).get(0);
		return PayOut.from(order, item, pay);
	}

}
*/